package de.yogularm.minecraft.itemfinder.gui;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import org.jdesktop.swingx.JXTable;
import de.yogularm.minecraft.itemfinder.region.DroppedItem;
public class ItemList {
private Component component;
private JXTable table;
private ItemTableModel model;
private TableRowSorter<ItemTableModel> sorter;
private JPopupMenu contextMenu;
public ItemList() {
initUI();
}
private void initUI() {
model = new ItemTableModel();
table = new JXTable(model);
sorter = new TableRowSorter<>(model);
table.setRowSorter(sorter);
sorter.setComparator(0, new NaturalOrderComparator()); // for item name
sorter.setSortKeys(Arrays.asList(
new RowSorter.SortKey(4, SortOrder.DESCENDING),
new RowSorter.SortKey(3, SortOrder.ASCENDING)));
table.getColumnModel().getColumn(0).setWidth(200);
component = new JScrollPane(table);
contextMenu = new JPopupMenu();
JMenuItem copyItem = new JMenuItem("Copy");
copyItem.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent actionEvent) {
Object text = table.getValueAt(table.getSelectedRow(), table.getSelectedColumn());
if (text == null) {
return;
}
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(text.toString()), null);
}
});
contextMenu.add(copyItem);
// manually show the popup menu so that the cell under the mouse is selected first
table.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// Left mouse click
if (SwingUtilities.isLeftMouseButton(e)) {
// Do something
}
// Right mouse click
else if (SwingUtilities.isRightMouseButton(e)) {
// get the coordinates of the mouse click
Point p = e.getPoint();
// get the row index that contains that coordinate
int rowNumber = table.rowAtPoint(p);
// Get the ListSelectionModel of the JTable
ListSelectionModel model = table.getSelectionModel();
// set the selected interval of rows. Using the "rowNumber"
// variable for the beginning and end selects only that one row.
model.setSelectionInterval(rowNumber, rowNumber);
int colNumber = table.columnAtPoint(p);
table.getColumnModel().getSelectionModel().setSelectionInterval(colNumber, colNumber);
contextMenu.show(table, p.x, p.y);
}
}
});
}
public void setItems(List<DroppedItem> items) {
model.setItems(items);
table.packAll(); // adjust column widths
}
public Component getComponent() {
return component;
}
private static class ItemTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1904800093497922295L;
private static final String[] COLUMNS = new String[] { "Item Name",
"Stack Size", "Location", "Age", "Chunk Update" };
private List<DroppedItem> items;
public ItemTableModel() {
this.items = new ArrayList<>();
}
public void setItems(List<DroppedItem> items) {
this.items = items;
fireTableDataChanged();
}
@Override
public int getColumnCount() {
return COLUMNS.length;
}
@Override
public String getColumnName(int column) {
return COLUMNS[column];
}
@Override
public int getRowCount() {
return items.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (rowIndex >= items.size())
return "";
DroppedItem item = items.get(rowIndex);
switch (columnIndex) {
case 0:
return item.getName();
case 1:
return item.getCount();
case 2:
return item.getPosition().toRoundedString();
case 3:
// there are items with age 0 which should be displayed at the bottom
// HourSecond will render Integer.MAX_VALUE as --
return new HourSecond(item.getAge() == 0 ? Integer.MAX_VALUE : item.getAge() / 20);
case 4:
return new RelativeTime(- item.getRelativeChunkUpdateTime());
default:
return "";
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Integer.class;
case 2:
return String.class;
case 3:
return HourSecond.class;
case 4:
return RelativeTime.class;
default:
return null;
}
}
}
}